package com.pdool.h5red;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.HMac;
import cn.hutool.crypto.digest.HmacAlgorithm;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.Date;
import java.util.Set;

/**
 * @author 种鑫
 * @date 2023/12/19 10:22
 */
@Service
@Slf4j
public class GameService {
    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Resource
    GameConfig gameConfig;

    JSONObject err = JSON.parseObject("{\"meta\":{\"error\":[{\"code\":\"3001\",\"message\":\"服务器异常\"}]}}");

    public boolean checkGameData(RoundInfoDTO roundInfoDTO) {
        long score = roundInfoDTO.getScore();
        if (score >= gameConfig.getMaxScore()) {
            return false;
        }
        return true;
    }

    public JSONObject saveMaxScore(String uid, RoundInfoDTO roundInfoDTO) {
        String setName = Constants.SCORE + uid;
        //当前日期字符串，格式：yyyy-MM-dd
        String today = getTodayStr();
        Double score1 = stringRedisTemplate.opsForZSet().score(setName, today);
        //  1、每天都有分数
        if (score1 == null) {
            //  今天第一次
            stringRedisTemplate.opsForZSet().add(setName, today, roundInfoDTO.getScore());
            //  记录今天的完成次数
            String accKey = Constants.FINISH_ACC + today;
            stringRedisTemplate.opsForValue().increment(accKey);

        } else {
            //  更新最大分数
            if (roundInfoDTO.getScore() >= score1) {
                stringRedisTemplate.opsForZSet().add(setName, today, roundInfoDTO.getScore());
            }
        }
        // 发奖
        String rewardSetName = Constants.REWARD + uid;

        Boolean member = stringRedisTemplate.opsForSet().isMember(rewardSetName, today);
        if (member == null || !member) {
            Long size = stringRedisTemplate.opsForSet().size(rewardSetName);
            size = size == null ? 0L : size;
            if (size < 7) {
                JSONObject jsonObject = sendReward(uid, roundInfoDTO);
                Boolean byPath = (Boolean) jsonObject.getByPath("$.meta.succ");
                if (byPath != null && byPath) {//  发奖成功
                    //  记录发奖次数
                    stringRedisTemplate.opsForSet().add(rewardSetName, today);
                }
                return jsonObject;
            }
        }

        return null;

    }

    private JSONObject sendReward(String uid, RoundInfoDTO roundInfoDTO) {
        try {
            String json = makeRewardJson(uid);
            String sig = makeSign(json);
            String url = gameConfig.getAuthServer() + "/webview/api/open/send-award";
            String result = HttpRequest.post(url)
                    .header("X-Signature", sig)
                    .header("Authorization", roundInfoDTO.getAuthorization())
                    .body(json)
                    .execute().body();
            log.error("http result   {} ", result);
//            String result = "{\n" +
//                    "  \"meta\": {\n" +
//                    "    \"ver\": \"1.0\",\n" +
//                    "    \"succ\": true,\n" +
//                    "    \"error\": null\n" +
//                    "  },\n" +
//                    "  \"paload\": null\n" +
//                    "}";
            JSONObject jsonObject = JSON.parseObject(result);
//            JSONObject jsonObject = new JSONObject();
//            jsonObject.putByPath("meta.succ",true);
            return jsonObject;
        } catch (Exception e) {
            log.error("",e);
            return err;
        }

    }


    private String makeSign(String json) {

        HMac mac = new HMac(HmacAlgorithm.HmacSHA256, gameConfig.getSecretKey().getBytes());
        String s = mac.digestBase64(json, false);
        return s;
    }

    private String makeRewardJson(String uid) {
        String rewardSetName = Constants.REWARD + uid;

        Long size = stringRedisTemplate.opsForSet().size(rewardSetName);
        size = size == null ? 0L : size;
        String mailTitle = "《山海经的红包雨?!》网页活动奖励（第{}次）";
        long groupId = size + 1;

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("webId", "1003");
        jsonObject.put("mailTitle", StrUtil.format(mailTitle, groupId));
        jsonObject.put("groupId", groupId);

        return jsonObject.toString();
    }

    public TodayScoreDTO queryTodayInfo(String uid) {
        String today = getTodayStr();
        String setName = Constants.SCORE + uid;
        ZSetOperations.TypedTuple<String> maxScoreInSortedSet = findMaxScoreInSortedSet(setName);
        String day = null;
        Double maxScore = 0D;
        if (maxScoreInSortedSet != null) {
            day = maxScoreInSortedSet.getValue();
            maxScore = maxScoreInSortedSet.getScore();
        }
        boolean hasReward = false;
        String rewardSetName = Constants.REWARD + uid;
        Boolean member = stringRedisTemplate.opsForSet().isMember(rewardSetName, today);
        if (member != null && member) {
            hasReward = true;
        }
        Long size = stringRedisTemplate.opsForSet().size(rewardSetName);
        size = size == null ? 0L : size;

        return new TodayScoreDTO(day, maxScore, hasReward, size, System.currentTimeMillis());
    }

    public ZSetOperations.TypedTuple<String> findMaxScoreInSortedSet(String key) {
        // 查询有序集合中的最大分数
        Set<ZSetOperations.TypedTuple<String>> maxValues = stringRedisTemplate.opsForZSet().reverseRangeWithScores(key, 0, 0);

        // 如果存在最大值，返回其分数
        if (maxValues != null && !maxValues.isEmpty()) {
            return maxValues.iterator().next();
        } else {
            // 如果没有数据，返回空或者适当的默认值
            return null;
        }
    }


    public void openGame(String uid) {
        String today = getTodayStr();
        String keyName = MessageFormat.format(Constants.OPEN, today, uid);
        long l = System.currentTimeMillis();
        Boolean hasKey = stringRedisTemplate.hasKey(keyName);
        if (hasKey != null && hasKey) {
            return;
        }
        stringRedisTemplate.opsForValue().set(keyName, String.valueOf(l));
        String accKey = Constants.OPEN_ACC + today;
        stringRedisTemplate.opsForValue().increment(accKey);

    }


    public static String getTodayStr() {
        int hour = DateUtil.hour(new Date(), true);
        if (hour < 4) {
            return DateUtil.formatDate(DateUtil.yesterday());
        } else {
            return DateUtil.today();
        }
    }


}
